package com.yh.lq.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yh.lq.LQGlobal;
import com.yh.lq.boot.EventProperties;
import com.yh.lq.entity.ImType;
import com.yh.lq.robot.ApiHandler;
import com.yh.lq.robot.EventHandler;
import com.yh.lq.robot.LQ;
import com.yh.lq.robot.LQFactory;
import com.yh.lq.utils.AesUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


/**
 * ws处理类
 * <p>
 * 建立连接
 * 断开连接
 * 收到消息
 */
@Slf4j
public class LQWebSocketHandler extends TextWebSocketHandler {

    private LQFactory lQFactory;
    private ApiHandler apiHandler;
    private EventHandler eventHandler;
    private ExecutorService executor;


    public LQWebSocketHandler(EventProperties eventProperties, LQFactory lQFactory, ApiHandler apiHandler, EventHandler eventHandler) {
        this.lQFactory = lQFactory;
        this.apiHandler = apiHandler;
        this.eventHandler = eventHandler;
        this.executor =
                new ThreadPoolExecutor(eventProperties.getCorePoolSize(),
                        eventProperties.getMaxPoolSize(),
                        eventProperties.getKeepAliveTime(),
                        TimeUnit.MILLISECONDS,
                        new ArrayBlockingQueue<>(eventProperties.getWorkQueueSize()));
    }

    /**
     * ws建立连接，创建LQ对象，并放入LQGlobal.robots，是static Map，方便在jar外面获取
     *
     * @param session websocket session
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
        log.info("ws connect");
    }

    /**
     * ws连接断开，需要清除之前的CoolQ对象
     *
     * @param session websocket session
     * @param status  状态码
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
        LQ lq = LQGlobal.sessionRobotMap.get(session.getId());
        if (lq == null) {
            return;
        }
        String selfId = lq.getSelfId();
        log.info(selfId + " disconnected!");
        LQGlobal.robots.remove(selfId);
    }

    /**
     * ws收到消息时的方法
     * 可能是api响应（包含echo字段）
     * 可能是事件上报
     *
     * @param session websocketSession
     * @param message 消息内容
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) {
        String receiveMsg=message.getPayload();
        if(!StringUtils.isEmpty(lQFactory.getLqProperties().getRobotSecretKey())){
            try {
                receiveMsg= AesUtil.aesDecrypt(receiveMsg,lQFactory.getLqProperties().getRobotSecretKey());
            } catch (Exception e) {
                e.printStackTrace();
                log.error("解密失败",e);
                return;
            }
        }
        JSONObject recvJson = JSON.parseObject(receiveMsg);
        log.info("receive msg：{}", recvJson);
        boolean isApiReturn = recvJson.containsKey("echo");
        if (isApiReturn) {
            apiHandler.onReceiveApiMessage(recvJson);
            return;
        }
        if (recvJson.containsKey("Code")) {
            log.warn("may error:{}", recvJson);
            return;
        }
        if (recvJson.getInteger("imType")!=null && ImType.WE_CHAT.getIndex() == recvJson.getInteger("imType")) {
            processWeChatMsg(recvJson, session);
        } else {
            processQQMsg(recvJson, session);
        }

    }

    /**
     * 初始化bot
     *
     * @param xSelfId
     * @param session
     * @return
     */
    public LQ createRobot(Long xSelfId, WebSocketSession session) {
        LQ robot = lQFactory.createCoolQ(xSelfId, session);
        LQGlobal.robots.put(String.valueOf(xSelfId), robot);
        LQGlobal.sessionRobotMap.put(session.getId(), robot);
        return robot;
    }

    public LQ createRobot(String robotId, ImType imType, WebSocketSession session) {
        LQ robot = lQFactory.createRobot(robotId, imType, session);
        LQGlobal.robots.put(robotId, robot);
        LQGlobal.sessionRobotMap.put(session.getId(), robot);
        return robot;
    }

    public void processQQMsg(JSONObject recvJson, WebSocketSession session) {
        Long xSelfId = recvJson.getLong("Robot");
        if (xSelfId == null) {
            log.warn("非QQ机器人连接，过滤掉");
            return;
        }
        LQ robot = LQGlobal.robots.get(String.valueOf(xSelfId));
        // 防止网络问题，快速重连可能 （连接1，断开1，连接2） 变成 （连接1，连接2，断开1）
        if (robot == null) {
            log.info(xSelfId + " connected!");
            robot = createRobot(xSelfId, session);
        }
        robot.setBotSession(session);
        //如果当前session匹配没找到robot，则重新匹配
        if (!LQGlobal.sessionRobotMap.containsKey(session.getId())) {
            LQGlobal.sessionRobotMap.put(session.getId(), robot);
        }
        LQ finalRobot = robot;
        executor.execute(() -> eventHandler.handle(finalRobot, recvJson));
    }

    public void processWeChatMsg(JSONObject recvJson, WebSocketSession session) {
        String xSelfId = recvJson.getString("weChatRobot");
        if (xSelfId == null) {
            log.warn("非微信机器人连接，过滤掉");
            return;
        }
        LQ robot = LQGlobal.robots.get(xSelfId);
        // 防止网络问题，快速重连可能 （连接1，断开1，连接2） 变成 （连接1，连接2，断开1）
        if (robot == null) {
            log.info(xSelfId + " connected!");
            robot = createRobot(xSelfId, ImType.WE_CHAT, session);
        }
        robot.setBotSession(session);
        //如果当前session匹配没找到robot，则重新匹配
        if (!LQGlobal.sessionRobotMap.containsKey(session.getId())) {
            LQGlobal.sessionRobotMap.put(session.getId(), robot);
        }
        LQ finalRobot = robot;
        executor.execute(() -> eventHandler.handle(finalRobot, recvJson));
    }
}
